Jerry's Log

Database Locks

contents

1. 데이터베이스 락(Lock)이란?

락(Lock) 은 데이터베이스 엔진이 여러 사용자가 동시에 같은 데이터에 접근할 때 데이터의 일관성을 유지하기 위해 사용하는 동기화 메커니즘입니다.

비유: 비행기 화장실을 생각해보세요.


2. 락의 두 가지 주요 유형 (Lock Modes)

"읽기(Reading)"와 "쓰기(Writing)"의 차이를 이해하는 것이 핵심입니다.

A. 공유 잠금 (Shared Lock / S-Lock) – "독자를 위한 잠금"

B. 배타적 잠금 (Exclusive Lock / X-Lock) – "저자를 위한 잠금"

호환성 매트릭스 (The Compatibility Matrix):

현재 걸려있는 락 사용자 B가 읽기(S) 요청 사용자 B가 쓰기(X) 요청
없음 (None) ✅ 허용됨 ✅ 허용됨
읽기 (S) ✅ 허용됨 ❌ 대기 (WAIT)
쓰기 (X) ❌ 대기 (WAIT) ❌ 대기 (WAIT)

3. 잠금 단위 (Lock Granularity)

데이터베이스가 한 번에 얼마나 많은 데이터를 잠글까요?

  1. 행(Row) 수준 잠금:
    • 특정 행 하나만 잠급니다 (예: User ID 5).
    • 장점: 동시성이 높음 (다른 사람들은 User ID 6을 건드릴 수 있음).
    • 단점: 메모리 오버헤드가 큼 (수백만 개의 작은 자물쇠를 관리하는 것은 비쌈).
  2. 페이지(Page) 수준 잠금:
    • 저장소의 "페이지"(예: User ID 1~50이 들어있는 8KB 블록) 단위를 잠급니다.
    • 중간 단계입니다.
  3. 테이블(Table) 수준 잠금:
    • Users 테이블 전체를 통째로 잠급니다.
    • 장점: 오버헤드가 매우 적음 (관리할 자물쇠가 딱 하나).
    • 단점: 동시성 제로. 모든 사람이 기다려야 함. 주로 ALTER TABLE(스키마 변경) 작업 시 사용됩니다.

락 에스컬레이션 (Lock Escalation): 만약 트랜잭션이 너무 많은 행 락(예: 10만 개 행 업데이트)을 얻으려고 하면, DB는 메모리를 아끼기 위해 자동으로 테이블 락으로 "승격(Escalation)"시켜버립니다. 이 순간 다른 모든 사용자가 갑자기 차단될 수 있습니다.


4. 비관적 락 vs. 낙관적 락 (Pessimistic vs. Optimistic)

애플리케이션 개발자에게 가장 중요한 개념입니다.

A. 비관적 락 (Pessimistic Locking - "아무도 믿지 마라")

충돌이 반드시 일어날 것이라고 가정하고, 데이터를 건드리기 전에 미리 잠가버립니다.

B. 낙관적 락 (Optimistic Locking - "잘 될 거야")

충돌이 드물 것이라고 가정합니다. DB 행을 잠그지 않습니다. 대신, 저장할 때 변경 여부를 확인합니다.


5. 교착 상태 (Deadlock - 죽음의 순환)

두 트랜잭션이 서로가 쥐고 있는 락을 놓기를 기다리며 무한 대기 상태에 빠지는 현상입니다.

시나리오:

DB의 대처:

데이터베이스에는 "Deadlock Detector(교착 상태 감지기)"라는 백그라운드 프로세스가 있습니다. 이것이 순환 고리를 감지하면, 둘 중 하나의 트랜잭션(희생자, Victim)을 강제로 종료(Kill) 시켜 다른 하나가 진행되도록 합니다.


6. 격리 수준 (Isolation Levels)

락은 트랜잭션 격리 수준을 구현하는 도구입니다. 수준이 엄격할수록 더 많은 락을 사용합니다.

  1. Read Uncommitted: 읽기 락(S-Lock)을 안 씁니다. 남이 아직 커밋하지 않은 데이터도 읽을 수 있습니다 ("Dirty Read"). 가장 빠르지만 위험함.
  2. Read Committed (Postgres/SQL Server 기본값): 커밋된 데이터만 읽습니다. 짧은 순간만 S-Lock을 겁니다.
  3. Repeatable Read (MySQL 기본값): 트랜잭션 내내 한 번 읽은 행은 값이 변하지 않음을 보장합니다. 더 강력한 락이나 스냅샷을 사용합니다.
  4. Serializable: 가장 엄격합니다. "Phantom Read"(없던 행이 갑자기 생기는 현상)를 막기 위해 범위 락(Range Lock)을 겁니다. 사실상 트랜잭션을 한 줄로 세워서 처리합니다. 가장 느림.

7. MVCC (다중 버전 동시성 제어)

프로 팁: 현대적인 데이터베이스(PostgreSQL, MySQL InnoDB, Oracle)는 읽을 때 단순한 S-Lock을 잘 쓰지 않습니다. 대신 MVCC를 사용합니다.

요약 체크리스트

  1. 읽기(Read) 는 보통 다른 읽기를 허용합니다 (공유).
  2. 쓰기(Write) 는 모든 것을 막습니다 (배타적).
  3. 교착 상태(Deadlock) 는 A가 B를 기다리고, B가 A를 기다릴 때 발생합니다.
  4. 웹 API 환경에서는 DB 락보다 낙관적 락(버전 컬럼 사용) 이 더 유리할 때가 많습니다.

references